#include "iConfig.hpp"
#include <glf/core/event.h>

#include <glf/app.h>
#include <glf/input/inputEvent.h>
#include <glf/io/fileStream.h>
#include <algorithm>

#include <glf/debugger/packet.h>


namespace glf
{
const char* gAppEventNames[4] = {
	"AET_ORIENTATION",
	"AET_SYSTEM",
	"AET_DISPLAY",
};

const char* gInputEventNames[IET_INPUT_END - IET_INPUT_START] = {
	"IET_MOUSE_BTN_DOWN",
	"IET_MOUSE_BTN_UP",
	"IET_MOUSE_MOVED",
	"IET_MOUSE_WHEEL",		
	"IET_KEY_PRESSED",
	"IET_KEY_RELEASED",		
	"IET_GAMEPAD_CONNECTION",
	"IET_GAMEPAD_BUTTON_PRESSED",
	"IET_GAMEPAD_BUTTON_RELEASED",		
	"IET_GAMEPAD_CURSOR_IN",
	"IET_GAMEPAD_CURSOR_MOVED",
	"IET_GAMEPAD_CURSOR_OUT",
	"IET_GAMEPAD_SENSOR_STICK_CHANGED",
	"IET_GAMEPAD_SENSOR_ACCELEROMETER_CHANGED",
	"IET_GAMEPAD_SENSOR_GYROSCOPE_CHANGED",		
	"IET_TOUCHPAD_BEGAN",
	"IET_TOUCHPAD_MOVED",
	"IET_TOUCHPAD_ENDED",
};
const char* GetFlagName(ushort flag) {
	if(flag == 0)
		return "none";
	else if(flag == CoreEvent::FB_EXTERNAL)
		return "external";
	else if(flag == CoreEvent::FB_POSTED)
		return "posted";
	else if(flag == (CoreEvent::FB_EXTERNAL|CoreEvent::FB_POSTED))
		return "external+posted";
	
	return "unknown";
}

const char* gUserEvent = "UserEvent";

int GetEventIdFromName(const char* name) {
	for(int i= 0; i < int(asizeof(gAppEventNames)); ++i) {
		if(strcmp(gAppEventNames[i], name) == 0) {
			return i + APP_EVENT_TYPE_BASE;
		}
	}
	for(int i= 0; i < int(asizeof(gInputEventNames)); ++i) {
		if(strcmp(gInputEventNames[i], name) == 0) {
			return i + IET_INPUT_START;
		}
	}
	if(strcmp(gUserEvent, name) == 0) {
		return USER_EVENT_TYPE_BASE;
	}
	
	return -1;
}

const char* GetEventName(int evtId) {
	if(evtId >= APP_EVENT_TYPE_BASE && evtId < APP_EVENT_END) {
		return gAppEventNames[evtId - APP_EVENT_TYPE_BASE];
	} else if(evtId >= IET_INPUT_START && evtId < IET_INPUT_END) {
		return gInputEventNames[evtId - IET_INPUT_START];
	} else if(evtId >= USER_EVENT_TYPE_BASE) {
		return gUserEvent;
	} else {
		return "Unknown";
	}
}

//AppEventSerializer
class AppEventSerializer : public EventSerializer
{
public:
	static bool StaticSerialize(EventDataWriter &buffer, const glf::CoreEvent &event, ushort flags);
	static glf::CoreEvent* StaticUnserialize(glf::CoreEvent::DataType &data, EventDataReader &reader, ushort& flags) ;

	static bool StaticTextSerialize(std::stringstream& ss, const glf::CoreEvent &event, ushort flags);
	static glf::CoreEvent* StaticTextUnserialize(glf::CoreEvent::DataType &data, std::stringstream& ss, ushort& flags) ;

	bool Serialize(EventDataWriter &buffer, const glf::CoreEvent &event) const {
		return StaticSerialize(buffer, event, GetEventFlags(event));
	}
	
	glf::CoreEvent* Unserialize(glf::CoreEvent::DataType &data, EventDataReader &reader) const {
		glf::CoreEvent &evt = *reinterpret_cast<glf::CoreEvent *>(&data);
		return StaticUnserialize(data, reader, GetEventFlags(evt));
	}
};

//EventSerializer

const ushort &EventSerializer::GetEventFlags(const glf::CoreEvent &coreEvent) const
{
	return coreEvent.mFlags;
}

ushort &EventSerializer::GetEventFlags(glf::CoreEvent &coreEvent) const
{
	return coreEvent.mFlags;
}

//AppEventSerializer

bool AppEventSerializer::StaticTextSerialize(std::stringstream& ss, const glf::CoreEvent &evt, ushort flags)
{
	ss	<< GetEventName(evt.mType) << " " << evt.mType 
		<< " " << GetFlagName(flags) << " " << flags;
	
	switch (evt.mType)
	{
	case AET_SYSTEM:
		{
			const SystemEvent &sysEvt = static_cast<const SystemEvent &>(evt);
			ss << " " << sysEvt.mSubType
			<< "\n";
			return true;
		}
	case AET_ORIENTATION:
		{
			const OrientationEvent &oriEvt = static_cast<const OrientationEvent &>(evt);
			ss << " " << oriEvt.mSubType
			<< "\n";

			return true;
		}
	case AET_DISPLAY:
		{
			const DisplayEvent& dispEvt = static_cast<const DisplayEvent&>(evt);
			ss	<< " " << dispEvt.mSubType
				<< " " << dispEvt.mCurrentResolution
				<< " " << dispEvt.mRank;
			
			for(int i = 0; i < dispEvt.mResolutionCount; ++i) {
				ss	<< " " << dispEvt.mResolutions[i].x
					<< " " << dispEvt.mResolutions[i].y;
			}

			ss << "\n";
			
			return true;
		}
	case IET_MOUSE_BTN_DOWN:
	case IET_MOUSE_BTN_UP:
	case IET_MOUSE_MOVED:
	case IET_MOUSE_WHEEL:
		{
			const MouseEvent &msEvt = static_cast<const MouseEvent &>(evt);
			
			const Point<float> normalizedPos =
				App::GetInstance()->ConvertPosScreenToNormalizedScreen(msEvt.mPos);
			
			ss	<< " " << GetAppInputMgr().GetMouseIndex(msEvt.mInputDevice)
				<< " " << msEvt.mBtn
				<< " " << normalizedPos.x << " " << normalizedPos.y << " " << msEvt.mWheel
				<< "\n";

			return true;
		}
	case IET_KEY_PRESSED:
	case IET_KEY_RELEASED:
		{
			const KeyboardEvent &kbEvt = static_cast<const KeyboardEvent &>(evt);
			ss	<< " " << GetAppInputMgr().GetKeyboardIndex(kbEvt.mInputDevice)
				<< " " << kbEvt.mChar
				<< " " << kbEvt.mKey
				<< " " << kbEvt.mModifiers
				<< "\n";
			return true;
		}
	case IET_TOUCHPAD_BEGAN:
	case IET_TOUCHPAD_MOVED:
	case IET_TOUCHPAD_ENDED:
		{
			const TouchPadEvent &tpEvt = static_cast<const TouchPadEvent &>(evt);

			const Point<float> normalizedPos =
				App::GetInstance()->ConvertPosScreenToNormalizedScreen(tpEvt.mPoint);

			ss	<< " " << GetAppInputMgr().GetGamepadIndex(tpEvt.mInputDevice)
				<< " " << tpEvt.mTouchPadIndex
				<< " " << tpEvt.mTouchId
				<< " " << normalizedPos.x
				<< " " << normalizedPos.y
				<< "\n";
			return true;
		}
	case IET_GAMEPAD_SENSOR_STICK_CHANGED:
	case IET_GAMEPAD_SENSOR_ACCELEROMETER_CHANGED:
	case IET_GAMEPAD_SENSOR_GYROSCOPE_CHANGED:
		{
			const GamepadSensorEvent &sensorEvt = static_cast<const GamepadSensorEvent &>(evt);
			ss	<< " " << GetAppInputMgr().GetGamepadIndex(sensorEvt.mInputDevice)
				<< " " << sensorEvt.mSensorIndex
				<< " " << sensorEvt.mValue.x
				<< " " << sensorEvt.mValue.y
				<< " " <<	sensorEvt.mValue.z
				<< "\n";
			return true;
		}
	}
	
	return false;
}

bool AppEventSerializer::StaticSerialize(EventDataWriter &writer, const glf::CoreEvent &evt, ushort flags)
{
	writer.Write(evt.mType);
	writer.Write(flags);
	switch (evt.mType)
	{
	case AET_SYSTEM:
		{
			const SystemEvent &sysEvt = static_cast<const SystemEvent &>(evt);
			writer.Write(sysEvt.mSubType);
			return true;
		}
	case AET_ORIENTATION:
		{
			const OrientationEvent &oriEvt = static_cast<const OrientationEvent &>(evt);
			writer.Write(oriEvt.mSubType);
			return true;
		}
	case IET_MOUSE_BTN_DOWN:
	case IET_MOUSE_BTN_UP:
	case IET_MOUSE_MOVED:
	case IET_MOUSE_WHEEL:
		{
			const MouseEvent &msEvt = static_cast<const MouseEvent &>(evt);
			writer.Write((int)GetAppInputMgr().GetMouseIndex(msEvt.mInputDevice));
			writer.Write(msEvt.mBtn);
			const Point<float> normalizedPos =
				App::GetInstance()->ConvertPosScreenToNormalizedScreen(msEvt.mPos);
			writer.Write(normalizedPos.x);
			writer.Write(normalizedPos.y);
			writer.Write(msEvt.mWheel);
			return true;
		}
	case IET_KEY_PRESSED:
	case IET_KEY_RELEASED:
		{
			const KeyboardEvent &kbEvt = static_cast<const KeyboardEvent &>(evt);
			writer.Write((int)GetAppInputMgr().GetKeyboardIndex(kbEvt.mInputDevice));
			writer.Write(kbEvt.mChar);
			writer.Write(kbEvt.mKey);
			writer.Write(kbEvt.mModifiers);
			return true;
		}
	case IET_TOUCHPAD_BEGAN:
	case IET_TOUCHPAD_MOVED:
	case IET_TOUCHPAD_ENDED:
		{
			const TouchPadEvent &tpEvt = static_cast<const TouchPadEvent &>(evt);
			writer.Write((int)GetAppInputMgr().GetGamepadIndex(tpEvt.mInputDevice));
			writer.Write(tpEvt.mTouchPadIndex);
			writer.Write(tpEvt.mTouchId);
			const Point<float> normalizedPos =
				App::GetInstance()->ConvertPosScreenToNormalizedScreen(tpEvt.mPoint);
			writer.Write(normalizedPos.x);
			writer.Write(normalizedPos.y);
			return true;
		}
	case IET_GAMEPAD_SENSOR_STICK_CHANGED:
	case IET_GAMEPAD_SENSOR_ACCELEROMETER_CHANGED:
	case IET_GAMEPAD_SENSOR_GYROSCOPE_CHANGED:
		{
			const GamepadSensorEvent &sensorEvt = static_cast<const GamepadSensorEvent &>(evt);
			writer.Write((int)GetAppInputMgr().GetGamepadIndex(sensorEvt.mInputDevice));
			writer.Write(sensorEvt.mSensorIndex);
			writer.Write(sensorEvt.mValue.x);
			writer.Write(sensorEvt.mValue.y);
			writer.Write(sensorEvt.mValue.z);
			return true;
		}
	}
	return false;
}


glf::CoreEvent *AppEventSerializer::StaticTextUnserialize(glf::CoreEvent::DataType &data, std::stringstream& ss, ushort& flags)
{
	glf::CoreEvent &evt = *reinterpret_cast<glf::CoreEvent *>(&data);
	std::string eventName, flagName;

	ss >> eventName >> evt.mType >> flagName >> flags;

	switch (evt.mType)
	{
	case AET_SYSTEM:
		{
			SystemEvent &sysEvt = static_cast<SystemEvent &>(evt);
			ss >> (int&)sysEvt.mSubType;
			return &evt;
		}
	case AET_ORIENTATION:
		{
			OrientationEvent &oriEvt = static_cast<OrientationEvent &>(evt);
			ss >> (int&)oriEvt.mSubType;
			return &evt;
		}
	case IET_MOUSE_BTN_DOWN:
	case IET_MOUSE_BTN_UP:
	case IET_MOUSE_MOVED:
	case IET_MOUSE_WHEEL:
		{
			MouseEvent &msEvt = static_cast<MouseEvent &>(evt);
			
			int index;
			ss >> index;
			msEvt.mInputDevice = &GetAppInputMgr().GetMouse(index);
			Point<float> normalizedDevice;
			ss	>> (int&)msEvt.mBtn
				>> normalizedDevice.x
				>> normalizedDevice.y
				>> msEvt.mWheel;
			
			
			msEvt.mPos = App::GetInstance()->ConvertPosNormalizedScreenToScreen(normalizedDevice);
			return &evt;
		}
	case IET_KEY_PRESSED:
	case IET_KEY_RELEASED:
		{
			KeyboardEvent &kbEvt = static_cast<KeyboardEvent &>(evt);
			int index;
			ss >> index;
			kbEvt.mInputDevice = &GetAppInputMgr().GetKeyboard(index);
			ss	>> (ushort&)kbEvt.mChar
				>> (int&)kbEvt.mKey
				>> (int&)kbEvt.mModifiers;

			return &evt;
		}
	case IET_TOUCHPAD_BEGAN:
	case IET_TOUCHPAD_MOVED:
	case IET_TOUCHPAD_ENDED:
		{
			TouchPadEvent &tpEvt = static_cast<TouchPadEvent &>(evt);
			int index;
			ss >> index;
			tpEvt.mInputDevice = &GetAppInputMgr().GetGamepad(index);
			Point<float> normalizedDevice;

			ss	>> tpEvt.mTouchPadIndex
				>> tpEvt.mTouchId
				>> normalizedDevice.x
				>> normalizedDevice.y;
			tpEvt.mPoint = App::GetInstance()->ConvertPosNormalizedScreenToScreen(normalizedDevice);
			return &evt;
		}
	case IET_GAMEPAD_SENSOR_STICK_CHANGED:
	case IET_GAMEPAD_SENSOR_ACCELEROMETER_CHANGED:
	case IET_GAMEPAD_SENSOR_GYROSCOPE_CHANGED:
		{
			GamepadSensorEvent &sensorEvt = static_cast<GamepadSensorEvent &>(evt);
			int index;
			ss >> index;
			sensorEvt.mInputDevice = &GetAppInputMgr().GetGamepad(index);
			ss	>> sensorEvt.mSensorIndex
				>> sensorEvt.mValue.x
				>> sensorEvt.mValue.y
				>> sensorEvt.mValue.z;
			return &evt;
		}
	}
	return 0;
}


glf::CoreEvent *AppEventSerializer::StaticUnserialize(glf::CoreEvent::DataType &data, EventDataReader &reader, ushort& flags)
{
	glf::CoreEvent &evt = *reinterpret_cast<glf::CoreEvent *>(&data);
	reader.Read(evt.mType);
	reader.Read(flags);
	switch (evt.mType)
	{
	case AET_SYSTEM:
		{
			SystemEvent &sysEvt = static_cast<SystemEvent &>(evt);
			reader.Read((int &)sysEvt.mSubType);
			return &evt;
		}
	case AET_ORIENTATION:
		{
			OrientationEvent &oriEvt = static_cast<OrientationEvent &>(evt);
			reader.Read((int &)oriEvt.mSubType);
			return &evt;
		}
	case IET_MOUSE_BTN_DOWN:
	case IET_MOUSE_BTN_UP:
	case IET_MOUSE_MOVED:
	case IET_MOUSE_WHEEL:
		{
			MouseEvent &msEvt = static_cast<MouseEvent &>(evt);
			int index;
			reader.Read(index);
			msEvt.mInputDevice = &GetAppInputMgr().GetMouse(index);
			reader.Read((int &)msEvt.mBtn);
			Point<float> normalizedDevice;
			reader.Read(normalizedDevice.x);
			reader.Read(normalizedDevice.y);
			msEvt.mPos = App::GetInstance()->ConvertPosNormalizedScreenToScreen(normalizedDevice);
			reader.Read(msEvt.mWheel);
			return &evt;
		}
	case IET_KEY_PRESSED:
	case IET_KEY_RELEASED:
		{
			KeyboardEvent &kbEvt = static_cast<KeyboardEvent &>(evt);
			int index;
			reader.Read(index);
			kbEvt.mInputDevice = &GetAppInputMgr().GetKeyboard(index);
			reader.Read((uchar &)kbEvt.mChar);
			reader.Read((int &)kbEvt.mKey);
			reader.Read(kbEvt.mModifiers);
			return &evt;
		}
	case IET_TOUCHPAD_BEGAN:
	case IET_TOUCHPAD_MOVED:
	case IET_TOUCHPAD_ENDED:
		{
			TouchPadEvent &tpEvt = static_cast<TouchPadEvent &>(evt);
			int index;
			reader.Read(index);
			tpEvt.mInputDevice = &GetAppInputMgr().GetGamepad(index);
			reader.Read(tpEvt.mTouchPadIndex);
			reader.Read(tpEvt.mTouchId);
			Point<float> normalizedDevice;
			reader.Read(normalizedDevice.x);
			reader.Read(normalizedDevice.y);
			tpEvt.mPoint = App::GetInstance()->ConvertPosNormalizedScreenToScreen(normalizedDevice);
			return &evt;
		}
	case IET_GAMEPAD_SENSOR_STICK_CHANGED:
	case IET_GAMEPAD_SENSOR_ACCELEROMETER_CHANGED:
	case IET_GAMEPAD_SENSOR_GYROSCOPE_CHANGED:
		{
			GamepadSensorEvent &sensorEvt = static_cast<GamepadSensorEvent &>(evt);
			int index;
			reader.Read(index);
			sensorEvt.mInputDevice = &GetAppInputMgr().GetGamepad(index);
			reader.Read(sensorEvt.mSensorIndex);
			reader.Read(sensorEvt.mValue.x);
			reader.Read(sensorEvt.mValue.y);
			reader.Read(sensorEvt.mValue.z);
			return &evt;
		}
	}
	return 0;
}

//EventManager

EventManager::EventManager()
	: mReceiverCount(0)
	, mReceiverOrder(0)
	, mUserEventType(USER_EVENT_TYPE_BASE)
{
	//Orientation event
	RegisterFixedEventType<OrientationEvent>(AET_ORIENTATION, "glf::AET_ORIENTATION");
	//System event
	RegisterFixedEventType<SystemEvent>(AET_SYSTEM, "glf::AET_SYSTEM");
	//Display event
	RegisterFixedEventType<DisplayEvent>(AET_DISPLAY, "glf::AET_DISPLAY");
	//Mouse events
	RegisterFixedEventType<MouseEvent>(IET_MOUSE_BTN_DOWN, "glf::IET_MOUSE_BTN_DOWN");
	RegisterFixedEventType<MouseEvent>(IET_MOUSE_BTN_UP, "glf::IET_MOUSE_BTN_UP");
	RegisterFixedEventType<MouseEvent>(IET_MOUSE_MOVED, "glf::IET_MOUSE_MOVED");
	RegisterFixedEventType<MouseEvent>(IET_MOUSE_WHEEL, "glf::IET_MOUSE_WHEEL");
	//Keyboard events
	RegisterFixedEventType<KeyboardEvent>(IET_KEY_PRESSED, "glf::IET_KEY_PRESSED");
	RegisterFixedEventType<KeyboardEvent>(IET_KEY_RELEASED, "glf::IET_KEY_RELEASED");
	//Gamepad connection events
	RegisterFixedEventType<GamepadConnectionEvent>(IET_GAMEPAD_CONNECTION, "glf::IET_GAMEPAD_CONNECTION");
	//Gamepad button events
	RegisterFixedEventType<GamepadButtonEvent>(IET_GAMEPAD_BUTTON_PRESSED, "glf::IET_GAMEPAD_BUTTON_PRESSED");
	RegisterFixedEventType<GamepadButtonEvent>(IET_GAMEPAD_BUTTON_RELEASED, "glf::IET_GAMEPAD_BUTTON_RELEASED");	
	//Gamepad cursor events
	RegisterFixedEventType<GamepadCursorEvent>(IET_GAMEPAD_CURSOR_IN, "glf::IET_GAMEPAD_CURSOR_IN");
	RegisterFixedEventType<GamepadCursorEvent>(IET_GAMEPAD_CURSOR_MOVED, "glf::IET_GAMEPAD_CURSOR_MOVED");
	RegisterFixedEventType<GamepadCursorEvent>(IET_GAMEPAD_CURSOR_OUT, "glf::IET_GAMEPAD_CURSOR_OUT");	
	//Gamepad sensor event
	RegisterFixedEventType<GamepadSensorEvent>(IET_GAMEPAD_SENSOR_STICK_CHANGED, "glf::IET_GAMEPAD_SENSOR_STICK_CHANGED");
	RegisterFixedEventType<GamepadSensorEvent>(IET_GAMEPAD_SENSOR_ACCELEROMETER_CHANGED, "glf::IET_GAMEPAD_SENSOR_ACCELEROMETER_CHANGED");
	RegisterFixedEventType<GamepadSensorEvent>(IET_GAMEPAD_SENSOR_GYROSCOPE_CHANGED, "glf::IET_GAMEPAD_SENSOR_GYROSCOPE_CHANGED");
	//Touchpad events
	RegisterFixedEventType<TouchPadEvent>(IET_TOUCHPAD_BEGAN, "glf::IET_TOUCHPAD_BEGAN");
	RegisterFixedEventType<TouchPadEvent>(IET_TOUCHPAD_MOVED, "glf::IET_TOUCHPAD_MOVED");
	RegisterFixedEventType<TouchPadEvent>(IET_TOUCHPAD_ENDED, "glf::IET_TOUCHPAD_ENDED");	
	//Register serializer
	std::vector<int> serializedTypes;
	serializedTypes.push_back(AET_ORIENTATION);
	serializedTypes.push_back(AET_SYSTEM);
	serializedTypes.push_back(IET_MOUSE_BTN_DOWN);
	serializedTypes.push_back(IET_MOUSE_BTN_UP);
	serializedTypes.push_back(IET_MOUSE_MOVED);
	serializedTypes.push_back(IET_MOUSE_WHEEL);
	serializedTypes.push_back(IET_KEY_PRESSED);
	serializedTypes.push_back(IET_KEY_RELEASED);
	serializedTypes.push_back(IET_TOUCHPAD_BEGAN);
	serializedTypes.push_back(IET_TOUCHPAD_MOVED);
	serializedTypes.push_back(IET_TOUCHPAD_ENDED);
	serializedTypes.push_back(IET_GAMEPAD_SENSOR_STICK_CHANGED);
	serializedTypes.push_back(IET_GAMEPAD_SENSOR_ACCELEROMETER_CHANGED);
	serializedTypes.push_back(IET_GAMEPAD_SENSOR_GYROSCOPE_CHANGED);
	mAppEventSerializer = new AppEventSerializer;
	RegisterEventSerializer(serializedTypes, mAppEventSerializer);
}

EventManager::~EventManager()
{
	delete mAppEventSerializer;
}

std::string EventManager::GetEventName(int type)
{
	SpinLockScope lock(mSpinLock);
	std::map<int, TypeInfo>::const_iterator it = mEventInfos.find(type);
	if (it != mEventInfos.end())
		return it->second.mName;
	return "";
}

size_t EventManager::GetEventSize(int type)
{
	SpinLockScope lock(mSpinLock);
	std::map<int, TypeInfo>::const_iterator it = mEventInfos.find(type);
	if (it != mEventInfos.end())
		return it->second.mSize;
	return 0;
}

int EventManager::GetEventType(const char *eventName)
{
	SpinLockScope lock(mSpinLock);
	std::map<std::string, int>::const_iterator it = mEventTypes.find(eventName);
	if (it != mEventTypes.end())
		return it->second;
	return -1;
}

void EventManager::RegisterFixedEventType(int type, size_t size, const char *eventName)
{
	GLF_ASSERT(size < CoreEvent::MAX_SIZE);
	GLF_ASSERT(type >= 0 && type < USER_EVENT_TYPE_BASE);
	SpinLockScope lock(mSpinLock);
	GLF_ASSERT(mEventInfos.find(type) == mEventInfos.end());
	char eventNameAndType[256];
	if (!eventName)
		eventName = "glf::CoreEvent";
	Sprintf_s<256>(eventNameAndType, "%s#%d", eventName, type);
	mEventInfos[type].mName = eventNameAndType;
	mEventInfos[type].mSize = size;
	mEventInfos[type].mId = mEventInfos.size()-1;
}

int EventManager::RegisterUserEventType(int &type, const char *eventName, size_t size)
{
	GLF_ASSERT(size < CoreEvent::MAX_SIZE);
	if (type >= USER_EVENT_TYPE_BASE) //bypass: already registred
		return type;
	GLF_ASSERT(type < 0);
	SpinLockScope lock(mSpinLock);
	GLF_ASSERT(mEventTypes.find(eventName) == mEventTypes.end());
	mEventTypes[eventName] = mUserEventType;
	mEventInfos[mUserEventType].mName = eventName;
	mEventInfos[mUserEventType].mSize = size;
	mEventInfos[mUserEventType].mId = mEventInfos.size()-1;
	type = mUserEventType++;
	return type;
}

void EventManager::AddEventReceiver(EventReceiver* evtReceiver, int priority) {
	std::vector<int> allowedEventTypes;
	AddEventReceiver(evtReceiver, priority, allowedEventTypes);
}

void EventManager::AddEventReceiver(EventReceiver* evtReceiver, int priority, std::vector<int>& allowedEventTypes)
{
	SpinLockScope lock(mSpinLock);
	// Find existing event receiver
	EventReceiverData* erd = 0;
	for (EventReceiverDataList::iterator 
		it = mEventReceivers.begin(), end = mEventReceivers.end(); it != end; ++it) {		
		if ((*it).mRcv == evtReceiver) {
			// Already registred
			erd = &*it;
			break;
		}
	}
	if (!erd) {
		// Create a new event receiver data
		mEventReceivers.resize(mEventReceivers.size() + 1);
		erd = &mEventReceivers.back();
		mReceiverCount++;
	}
	// Init receiver data
	erd->mRcv = evtReceiver;
	erd->mOrder = mReceiverOrder++;
	erd->mPriotity = priority;
	erd->mAllowedEvents.clear();
	// Build bit array of allowed events
	for (int i = 0; i < (int)allowedEventTypes.size(); ++i) {
		const int eventIndex = mEventInfos[allowedEventTypes[i]].mId;
		if (eventIndex > (int)erd->mAllowedEvents.size()-1) 
			erd->mAllowedEvents.resize(eventIndex+1);
		erd->mAllowedEvents[eventIndex] = true;		
	}
	mEventReceivers.sort();	
}

bool EventManager::HasEventReceiver() const
{
	return mReceiverCount > 0;
}

void
EventManager::PostEvent(const glf::CoreEvent &event)
{
	SpinLockScope lock(mSpinLock);
	//check if it is a registred event
	std::map<int, TypeInfo>::const_iterator it = mEventInfos.find(event.mType);
	GLF_ASSERT(it != mEventInfos.end());
	CoreEvent::DataType data;
	memcpy(&data, &event, it->second.mSize);
	reinterpret_cast<CoreEvent &>(data).MarkAsPosted();
	mEventQueue.push(data);
}

bool
EventManager::SendEvent(const glf::CoreEvent &event)
{
	// Check if it is a registred event
	GLF_ASSERT(mEventInfos.find(event.mType) != mEventInfos.end());
	return RaiseEvent(const_cast<CoreEvent &>(event));
}

bool EventManager::RaiseEvent(CoreEvent &evt)
{
	if (!PreSendEvent(evt) || !HasEventReceiver())
		return false;
	const int eventIndex = mEventInfos[evt.mType].mId;
	// Loop on all receivers
	for (EventReceiverDataList::const_iterator 
		it = mEventReceivers.begin(), end = mEventReceivers.end(); it != end; ++it) {		
		const EventReceiverData& erd = *it;
		EventReceiver *rcv = erd.mRcv;
		// Call rcv->OnEvent() if ...
		if (rcv->IsEnabled() && // receiver is enabled
			erd.IsEventAllowed(eventIndex) && // AND event type is allowed
			rcv->OnEvent(evt))
			// Stop event dispatching if event was consumed
			return true;
	}
	return false;
}

void EventManager::DispatchEvents()
{
	for(std::vector<Macro*>::iterator it = mMacros.begin(); it != mMacros.end(); ++it)
	{
		(*it)->UpdateFrame();
	}
	CoreEvent::DataType data;
	while (1) {
		//pop
		{
			SpinLockScope lock(mSpinLock);
			if (mEventQueue.empty())
				return;
			data = mEventQueue.front(); //copy
			mEventQueue.pop();
		}
		//raise
		glf::CoreEvent *event = reinterpret_cast<glf::CoreEvent *>(&data);
		RaiseEvent(*event);
	}
}

void EventManager::RemoveEventReceiver(EventReceiver* evtReceiver)
{
	SpinLockScope lock(mSpinLock);
	// Find receiver data
	for (EventReceiverDataList::iterator
		it = mEventReceivers.begin(), end = mEventReceivers.end(); it != end; ++it) {
		if (it->mRcv == evtReceiver) {
			// Erase receiver data
			mEventReceivers.erase(it);
			mReceiverCount--;
			break;
		}
	}
}

bool EventManager::PreSendEvent(CoreEvent &evt)
{
	switch (evt.mType)
	{
	case AET_ORIENTATION:
		{
			OrientationEvent &oriEvt = static_cast<OrientationEvent &>(evt);
			glf::App *app = glf::App::GetInstance();
			switch (oriEvt.mSubType)
			{
			case OET_ASPECTPORTRAIT:
				if (!app->SetOrientation(glf::ORIENTATION_PORTRAIT))
					return false;
				break;
			case OET_ASPECTLANDSCAPE_LEFT:
				if (!app->SetOrientation(glf::ORIENTATION_LANDSCAPE_LEFT))
					return false;
				break;
			case OET_ASPECTPORTRAIT_REVERSED:
				if (!app->SetOrientation(glf::ORIENTATION_PORTRAIT_REVERSED))
					return false;
				break;
			case OET_ASPECTLANDSCAPE_RIGHT:
				if (!app->SetOrientation(glf::ORIENTATION_LANDSCAPE_RIGHT))
					return false;
				break;
			case OET_ASPECTFACE_UP:
			case OET_ASPECTFACE_DOWN:
			default:
                break;
			}
		}
		return true;
	// Mouse
	case IET_MOUSE_BTN_DOWN:
	case IET_MOUSE_BTN_UP:
	case IET_MOUSE_MOVED:
	case IET_MOUSE_WHEEL:
	// Keyboard
	case IET_KEY_PRESSED:
	case IET_KEY_RELEASED:
	// Gamepad
	case IET_GAMEPAD_BUTTON_PRESSED:
	case IET_GAMEPAD_BUTTON_RELEASED:
	case IET_GAMEPAD_CURSOR_IN:
	case IET_GAMEPAD_CURSOR_MOVED:
	case IET_GAMEPAD_CURSOR_OUT:
	case IET_GAMEPAD_SENSOR_STICK_CHANGED:
	case IET_GAMEPAD_SENSOR_ACCELEROMETER_CHANGED:
	case IET_GAMEPAD_SENSOR_GYROSCOPE_CHANGED:
	// Touchpad
	case IET_TOUCHPAD_BEGAN:
	case IET_TOUCHPAD_MOVED:
	case IET_TOUCHPAD_ENDED:
		{
			InputEvent &inputEvt = static_cast<InputEvent &>(evt);
			return inputEvt.mInputDevice->PreSendEvent(inputEvt);
		}
	}
	return true;
}

EventSerializer *EventManager::GetEventSerializer(int type)
{
	SpinLockScope lock(mSpinLock);
	std::map<int, TypeInfo>::const_iterator it = mEventInfos.find(type);
	if (it != mEventInfos.end())
		return it->second.mSerializer;
	return 0;
}

void EventManager::RegisterEventSerializer(std::vector<int> types, EventSerializer *eventSerializer)
{
	SpinLockScope lock(mSpinLock);
	for (size_t i = 0, size = types.size(); i < size; ++i) {
		std::map<int, TypeInfo>::iterator it = mEventInfos.find(types[i]);
		if (it == mEventInfos.end()) {
			GLF_ASSERT(!"Can not add a serializer for an unregistred event.");
			continue;
		}
		it->second.mSerializer = eventSerializer;
	}
}

//------------------------------------------------------------------------------

static const ushort TYPE_SCREENSHOT(98);
static const ushort TYPE_NEW_FRAME(99);

Macro::Macro(EventManager& evtMgr, const std::string& filename, bool isLocal, ios::openflag loc )
	:	mEvtMgr(evtMgr)
	,	mFilename(filename.c_str())
	,	mIsLocal(isLocal)
	,	mLocation(loc)
	,	mMode(EM_DISABLED)
	,	mFramesWithoutEvent(0)
	,	mEventsThisFrame(0)
{
	mEvtMgr.RegisterMacro(this);

	if(mLocation == ios::none && isLocal)
		mLocation = ios::loc_home;

	Load(filename.c_str(), loc);
}

Macro::Macro(EventManager& evtMgr, debugger::PacketReader& in)
	:	mEvtMgr(evtMgr)
	,	mFilename()
	,	mIsLocal(false)
	,	mLocation(ios::none)
	,	mMode(EM_DISABLED)
	,	mFramesWithoutEvent(0)
	,	mEventsThisFrame(0)

{
	mEvtMgr.RegisterMacro(this);

	Load(in);
}

Macro::~Macro()
{
	mEvtMgr.UnregisterMacro(this);
	
	StopRecording();
	StopPlaying();
}

void Macro::StartRecording()
{
	if(mMode == EM_DISABLED)
	{
		mMode = EM_RECORDING;
		mEvtMgr.AddEventReceiver(this, EventManager::EP_HIGH);
		
		BroadcastEvent(EET_RECORDINGSTARTED, 0);
	}
	else if(mMode == EM_RECORDING)
	{
		StopRecording();
	}
}

void Macro::UpdateFrame()
{
	if(mMode == EM_RECORDING)
	{
		if(mEventsThisFrame == 0) {
			++mFramesWithoutEvent;
		}

		mEventsThisFrame = 0;
	}
	else if(mMode == EM_PLAYING)
	{
		++mFrame;

		if(mFramesWithoutEvent > 0)
		{
			--mFramesWithoutEvent;
		}
		else
		{

			int offset = (int)mStream.tellg();
			mStream.seekg(0, std::ios_base::end);
			int size = (int)mStream.tellg();
			mStream.seekg(offset);
			
			while((int)mStream.tellg() < size) {
				int offset = mStream.tellg();

				std::string evtName;
				ushort type;
				mStream >> evtName >> type;
				if(mStream.fail() || mStream.eof())
					break;
				
				if(type == TYPE_NEW_FRAME) {
					mStream >> mFramesWithoutEvent;
					
					return;
				} else {
					mStream.seekg(offset);
					
					ushort flags = 0;
					glf::CoreEvent::DataType data;
					AppEventSerializer::StaticTextUnserialize(data, mStream, flags);
					glf::CoreEvent& evt = *reinterpret_cast<glf::CoreEvent *>(&data);
					mEvtMgr.SendEvent(evt);
				}
			}

			BroadcastEvent(EET_PLAYBACKENDED, 0);
			
			StopPlaying();
		}
	}
}

void Macro::StopRecording()
{
	if(mMode == EM_RECORDING)
	{
		if(mEventsThisFrame == 0)
		{
			mStream << "NEW_FRAME" << " " << TYPE_NEW_FRAME << " " << (mFramesWithoutEvent+1) << "\n";

			mFramesWithoutEvent = 0;
		}

		BroadcastEvent(EET_RECORDINGFINISHED, 0);

		mEvtMgr.RemoveEventReceiver(this);
		mMode = EM_DISABLED;
	}
}

void Macro::StartPlaying()
{
	if(mMode == EM_DISABLED)
	{
		mMode = EM_PLAYING;

		mStream.seekg(0, std::ios::beg);

		mFramesWithoutEvent = 0;
		mFrame = 0;
		mTotalFrames = CountDuration();

		int offset = (int)mStream.tellg();
		mStream.seekg(0, std::ios::beg);

		BroadcastEvent(EET_PLAYBACKSTARTED, 0);
	} else if(mMode == EM_PAUSED) {

		mMode = EM_PLAYING;

		BroadcastEvent(EET_PLAYBACKUNPAUSED, 0);
	}
}

int Macro::CountDuration() {
	int startOffset = (int)mStream.tellg();
	mStream.seekg(0, std::ios_base::end);
	int size = (int)mStream.tellg();
	mStream.seekg(0, std::ios::beg);

	int numFrames = 0;
	
	while(mStream.tellg() < size) {
		int offset = (int)mStream.tellg();

		std::string evtName;
		ushort type;
		mStream >> evtName >> type;
		
		if(mStream.fail() || mStream.eof())
			break;
		
		if(type == TYPE_NEW_FRAME) {
			int framesWithoutEvent;
			mStream >> framesWithoutEvent;

			numFrames += framesWithoutEvent;
			
			continue;
		} else {

			mStream.seekg(offset);
			
			ushort flags = 0;
			glf::CoreEvent::DataType data;
			AppEventSerializer::StaticTextUnserialize(data, mStream, flags);
		}
	}

	mStream.seekg(startOffset, std::ios::beg);

	return numFrames;
}

void Macro::StopPlaying()
{
	if(mMode == EM_PLAYING || mMode == EM_PAUSED)
	{
		mMode = EM_DISABLED;
		mReader.reset();

		BroadcastEvent(EET_PLAYBACKSTOPPED, 0);
	}
}

void Macro::Pause()
{
	if(mMode == EM_PLAYING) {
		mMode = EM_PAUSED;
		BroadcastEvent(EET_PLAYBACKPAUSED, 0);
	} else if(mMode == EM_PAUSED) {
		mMode = EM_PLAYING;
		BroadcastEvent(EET_PLAYBACKPAUSED, 0);
	}
}

void Macro::SetData(const char* buf, int length) {
	mStream.str("");
	mStream.clear();
	mStream.write(buf, length);
}

void Macro::Save(const char* filename, ios::openflag flag)
{
	FileStream fs(filename, flag|ios::create|ios::trunc|ios::write);
	
	if(fs.IsOpened())
	{
		std::string data = mStream.str();
		fs.Write(data.c_str(), data.length());
	}
}

void Macro::Save(debugger::PacketWriter& pw)
{
#if GLF_ENABLE_DEBUGGER

	GLF_ASSERT(!mIsLocal);

	std::string data = mStream.str();
	
	pw.Write((int)data.size());
	pw.Write(data.c_str(), (int)data.size());
#endif
}

void Macro::Save()
{
	GLF_ASSERT(mIsLocal);

	stringc path = JoinPath(stringc("macros"), mFilename);

	FileStream fs(path.c_str(), mLocation|ios::create|ios::trunc|ios::write);
	if(fs.IsOpened()) {
		std::string data = mStream.str();
		fs.Write(data.c_str(), data.length());
	}
}

void Macro::Load(debugger::PacketReader& in) {
	if(IsRecording())
		StopRecording();
	if(IsPlaying() || IsPaused())
		StopPlaying();

#if GLF_ENABLE_DEBUGGER
	mIsLocal = in.ReadIntLE() ? true : false;
	
	debugger::stringdbg s = in.ReadString();
	mFilename = s.c_str();

	mStream.str("");
	mStream.clear();

	if(!mIsLocal) {
		int sizeOfBuf = in.ReadIntLE();
		std::vector<uchar> buf(sizeOfBuf);
		if(!buf.empty()) {
			in.Read(&buf[0], buf.size());
			mStream.write((char*)&buf[0], buf.size());
		}
	} else {
		mLocation = ios::loc_home;
	}
#endif
}

void Macro::Load(const char* filename, ios::openflag flag)
{
	if(IsRecording())
		StopRecording();
	if(IsPlaying() || IsPaused())
		StopPlaying();

	FileStream fs(filename, flag|ios::read);
	if(fs.IsOpened()) {
		std::vector<char> buffer(fs.GetSize());
		if(buffer.size()) {
			fs.Read(&buffer[0], buffer.size());

			mStream.str("");
			mStream.write(&buffer[0], buffer.size());
			mStream.clear();
			mStream.seekg(0);
		}

		mFramesWithoutEvent = 0;
	}
}

bool Macro::OnEvent(const CoreEvent& evt)
{
	if(std::find(mEventsToRecord.begin(), mEventsToRecord.end(), evt.mType) != mEventsToRecord.end())
	{
		if(mEventsThisFrame++ == 0)
		{
			mStream << "NEW_FRAME" << " " << TYPE_NEW_FRAME << " " << (mFramesWithoutEvent+1) << "\n";
			mFramesWithoutEvent = 0;
		}

		ushort flags = 0;
		
		AppEventSerializer::StaticTextSerialize(mStream, evt, flags);
	}

	return false;
}

}
